using System;
using System.Collections.Generic;
using System.IO;
using Gameplay.PVE.TurnBase;
using Gameplay.PVE.Utils;
using UnityEditor;
using UnityEngine;

namespace Gameplay.PVE.Editor
{

    public class SkillPlayerEditorWindow : EditorWindow
    {
        private static SkillPlayerEditorWindow Instance;
        public SkillPlayerEditorWindow()
        {
            Instance = this;
        }

        /*[MenuItem("GTATools/GamePlay/PVE/PveObstacle")]
        public static void SavePveObstacle()
        {
            
#if UNITY_EDITOR
            string path = string.Format("Assets/Arts/Pve/PveObstacle.txt");
            FileStream aFile = new FileStream(path, FileMode.OpenOrCreate);
            StreamWriter sw = new StreamWriter(aFile);
            string temp = string.Empty;
            var objects = GameObject.FindGameObjectsWithTag("PveObstacle");
            for (int i = 0; i < objects.Length; i++)
            {
                temp += objects[i].name + "\n";
                temp += objects[i].transform.position + "\n";
                temp += objects[i].transform.localEulerAngles + "\n";
                temp += "\n";
            }
            Debug.LogError(temp);
            sw.Write (temp);
            sw.Close();
            sw.Dispose();
#endif
        }*/
        
        [MenuItem("GTATools/GamePlay/PVE/SkillEditor")]
        public static void Init()
        {
            var window = EditorWindow.GetWindow<SkillPlayerEditorWindow>("战斗技能编辑器", true);
            Instance.Initialize();
        }
        
        private void Initialize()
        {
            timeScale = 1;
            actionList.Clear();
            for (int i = 0; i < _frameCount; i++)
            {
                actionList.Add(new SkillPlayerActionFrame
                {
                    hasAction = false,
                    frame = i,
                    actionName = string.Empty,
                });
            }
            eventList.Clear();
            for (int i = 0; i < _frameCount; i++)
            {
                eventList.Add(new SkillPlayerEventFrame
                {
                    elementId = 0,
                });
            }
            moveList.Clear();
            for (int i = 0; i < _frameCount; i++)
            {
                moveList.Add(new SkillPlayerMoveFrame
                {
                    hasPosition = false,
                    position = Vector3.zero,
                    frame = i,
                });
            }
        }
        Rect _frameListRect;
        Rect _timelineRect;
        Rect _scrollViewRect;
        Rect _scrollPosRect;
        private Rect infoRect;
        float titleHeight { get { return (EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing) * 3; } }
        float lineHeight { get { return 26; } }
        float actionListWidth { get { return 250; } }
        float scrollBarWidth { get { return 16; } }
        float _frameWidth = 10;//线条宽度
        float _frameCount = 200; //总帧数
        Vector2 _timelineMargin = new Vector2(50, 30);
        Vector2 _mainVerticalScroll;

        private int currentSelectedFrame = -1;
        private bool isSelectedAction = false;
        private bool isSelectedEvent = false;
        private bool isSelectedMove = false;

        private Vector2 timeFrameY;
        private Vector2 actionFrameY;
        private Vector2 eventFrameY;
        private Vector2 moveFrameY;
        private float uiHeight;

        private List<SkillPlayerActionFrame> actionList = new List<SkillPlayerActionFrame>();
        
        private List<SkillPlayerEventFrame> eventList = new List<SkillPlayerEventFrame>();
        
        private List<SkillPlayerMoveFrame> moveList = new List<SkillPlayerMoveFrame>();

        private GameObject hero;

        private bool isPlaying = false;
        
        private int heroId;
        private int skillId;

        private EditorAnimPlayer sourceHero;
        private EditorAnimPlayer targetHero;

        private float distance = 5;

        private double lastTime;

        private void OnGUI()
        {
            DrawBasic();
            
            float boxWidth = _timelineRect.xMin + _frameCount * _frameWidth;
            
            _frameListRect = Rect.MinMaxRect(_timelineMargin.x, 0, boxWidth, position.height);
            _timelineRect = Rect.MinMaxRect(_timelineMargin.x, 0, position.width  , titleHeight);
            uiHeight = titleHeight;
            DrawFrames();
            if (isSelectedAction)
            {
                DrawActionInfo();
            }

            if (isSelectedEvent)
            {
                DrawEventInfo();
            }
            
            if (isSelectedMove)
            {
                DrawMoveInfo();
            }
            
            UpdateInput();
            if (isPlaying && timeScale > 0)
            {
                progressX = _timelineMargin.x + (float)((EditorApplication.timeSinceStartup - startPlayingTime) * timeScale * PveUtils.fps) * 10;
                //DrawProgressLine(currentX);
            }
            DrawProgressLine();
        }

        private float progressX;
        
        private void DrawProgressLine()
        {
            var currentX = progressX;
            Handles.BeginGUI();
            Handles.color = Color.blue;
            Handles.DrawLine(new Vector3(currentX, 0), new Vector3(currentX, 400));
            Handles.EndGUI();
        }
        
        private void OnInspectorUpdate()
        {
            
        }
        
        private double startPlayingTime;
        private int lastFrame;
        private float lastSourceActionTime;
        private float lastTargetActionTime;

        private void UpdateFrame(int frame)
        {
            var action = actionList[frame];
            if (action.hasAction && frame != lastFrame)
            {
                sourceHero.Play(action.actionName);
                lastSourceActionTime = frame / PveUtils.fps;
            }
                
            var evnt = eventList[frame];
            if (evnt.elementId != 0 && frame != lastFrame)
            {
                targetHero.Play("Hit");
                lastTargetActionTime = frame / PveUtils.fps;
            }
        }
        
        private void Update()
        {
            Repaint();
            if (isPlaying && hero != null && timeScale > 0)
            {
                int frame = (int)((EditorApplication.timeSinceStartup - startPlayingTime) * timeScale * PveUtils.fps);
                if (frame >= _frameCount)
                {
                    isPlaying = false;
                }
                else
                {
                    UpdateFrame(frame);
                    UpdatePosition(startPlayingTime, EditorApplication.timeSinceStartup,timeScale);
                }
               
                var deltaTime = (EditorApplication.timeSinceStartup - lastTime) * timeScale;
                sourceHero?.Update(deltaTime);
                targetHero?.Update(deltaTime);
                lastTime = EditorApplication.timeSinceStartup;
                lastFrame = frame;
            }
        }

        private void UpdatePosition(double startTime, double currentTime,float timeScale)
        {
            if (hero == null)
            {
                return;
            }
            int frame = (int)((currentTime - startTime) * timeScale * PveUtils.fps);
            if (frame >= 0 && frame <= _frameCount)
            {
                Vector3 position = moveList[0].position;
                for (int i = 0; i < moveList.Count && i < frame; i++)
                {
                    position += 1 / PveUtils.fps * moveList[i].speed;
                }
                hero.transform.position = position;
            }
        }

        private void PlayTimeline()
        {
            isPlaying = true;
            startPlayingTime = EditorApplication.timeSinceStartup;
            lastTime = EditorApplication.timeSinceStartup;
            lastFrame = 0;
            if (hero == null)
            {
                return;
            }
            hero.transform.position = moveList[0].position;
            List<SkillPlayerMoveFrame> keyFrames = new List<SkillPlayerMoveFrame>();
            for (int i = 0; i < moveList.Count; i++)
            {
                if (moveList[i].hasPosition)
                {
                    keyFrames.Add(moveList[i]);
                }
            }

            for (int i = 0; i < keyFrames.Count - 1; i++)
            {
                int startFrame = keyFrames[i].frame;
                int endFrame = keyFrames[i + 1].frame;
                Vector3 distance = keyFrames[i + 1].position - keyFrames[i].position;
                float time = (endFrame - startFrame) / PveUtils.fps;
                Vector3 speed = distance / time;
                for (int j = startFrame; j < endFrame; j++)
                {
                    moveList[j].speed = speed;
                }
            }
        }

        private void DrawBasic()
        {
            GUI.Label(new Rect(5,5,100,20),"英雄id：");
            tempHeroId = GUI.TextField(new Rect(105, 5, 100, 20), tempHeroId);
            if (GUI.Button(new Rect(205, 5, 50, 20), "加载"))
            {
                int heroId;
                int.TryParse(tempHeroId, out heroId);
                var path = PveResourceManager.GetHeroPath(heroId);
                var hero = AssetDatabase.LoadAssetAtPath<GameObject>(path + ".prefab");
                var source = GameObject.Instantiate(hero);
                sourceHero = new EditorAnimPlayer();
                sourceHero.Initialize(source);
                this.heroId = heroId;
                this.hero = source;

                path = PveResourceManager.GetHeroPath(2004);
                hero = AssetDatabase.LoadAssetAtPath<GameObject>(path + ".prefab");
                var target = GameObject.Instantiate(hero);
                targetHero = new EditorAnimPlayer();
                targetHero.Initialize(target);
                target.transform.position = new Vector3(0,0,distance);
            }
            
            if (GUI.Button(new Rect(5, 25, 50, 20), "播放"))
            {
                PlayTimeline();
            }

            tempTimeScale = timeScale.ToString();
            tempTimeScale = GUI.TextField(new Rect(55, 25, 45, 20), tempTimeScale);
            float.TryParse(tempTimeScale, out timeScale);

            tempSkillId = GUI.TextField(new Rect(105, 25, 100, 20), tempSkillId);
            
            if (GUI.Button(new Rect(205, 25, 50, 20), "导出"))
            {
                SaveFile();
            }
        }

        private string tempHeroId;
        private string tempSkillId;
        private string tempTimeScale = "1";

        private float timeScale = 1;
        private float cachedTimeScale;
        
        private void SaveFile()
        {
#if UNITY_EDITOR
            int skillId;
            int.TryParse(tempSkillId, out skillId);
            string path = string.Format("Assets/Arts/Pve/HeroSkill{1}.txt",heroId,skillId);
            FileStream aFile = new FileStream(path, FileMode.OpenOrCreate);
            StreamWriter sw = new StreamWriter(aFile);
            string data = string.Empty;
            data += "Actions:\n";
            for (int i = 0; i < actionList.Count; i++)
            {
                if (actionList[i].hasAction)
                {
                    string line = actionList[i].frame + "|" + actionList[i].actionName;
                    line = line + "\n";
                    data = data + line;
                }
            }

            data += ";\n";
            data += "Events:\n";
            for (int i = 0; i < eventList.Count; i++)
            {
                if (eventList[i].elementId > 0)
                {
                    string line = i + "|" + eventList[i].elementId;
                    line = line + "\n";
                    data = data + line;
                }
            }

            data += ";\n";
            data += "Moves:\n";
            for (int i = 0; i < moveList.Count; i++)
            {
                if (moveList[i].hasPosition)
                {
                    string line = i + "|" + moveList[i].position;
                    line = line + "\n";
                    data = data + line;
                }
            }
            sw.Write (data);
            sw.Close();
            sw.Dispose();
#endif
        }
        
        private void DrawFrames()
        {
            var bgColor0 = Color.gray * 1.5f;
            var bgColor1 = _GetDividedColor(bgColor0);
            var timeBarRect = Rect.MinMaxRect(0, titleHeight, _frameListRect.xMax + 1, lineHeight + titleHeight);
            for (int i = 0; i < 6; i++)
            {
                timeBarRect.y = titleHeight + i * lineHeight;
                
                if (i == 0)
                {
                    DrawFrameLine(Rect.MinMaxRect(_frameListRect.xMin, titleHeight, _frameListRect.xMax + 1, lineHeight + titleHeight),
                        _frameWidth);
                }
                /*else if (i == 1)
                {
                    Common.DrawColorBox(timeBarRect, "", i % 2 == 0 ? bgColor0 : bgColor1);//背景
                }*/

                if (i == 1)
                {
                    GUI.Label(Rect.MinMaxRect(2,timeBarRect.yMin,50,timeBarRect.yMax),"动作");
                    for (int j = 0; j < _frameCount; j++)
                    {
                        float start = j * _frameWidth + _frameListRect.xMin;
                        float end = (j+1) * _frameWidth + _frameListRect.xMin;
                        var frameRect = Rect.MinMaxRect(start, timeBarRect.yMin, end-1, timeBarRect.yMax);
                    
                        var color = _GetBGColor(i,false);
                        color = actionList[j].hasAction ? Color.yellow : Color.white;
                        _DrawFrameBar(frameRect, color, 1);

                    }
                }
                else if (i == 3)
                {
                    GUI.Label(Rect.MinMaxRect(2,timeBarRect.yMin,50,timeBarRect.yMax),"元素");
                    for (int j = 0; j < _frameCount; j++)
                    {
                        float start = j * _frameWidth + _frameListRect.xMin;
                        float end = (j+1) * _frameWidth + _frameListRect.xMin;
                        var frameRect = Rect.MinMaxRect(start, timeBarRect.yMin, end-1, timeBarRect.yMax);
                    
                        var color = _GetBGColor(i,false);
                        color = eventList[j].elementId != 0 ? Color.red : Color.white;
                        _DrawFrameBar(frameRect, color, 1);
                    }
                }
                else if (i == 5)
                {
                    GUI.Label(Rect.MinMaxRect(2,timeBarRect.yMin,50,timeBarRect.yMax),"位置");
                    for (int j = 0; j < _frameCount; j++)
                    {
                        float start = j * _frameWidth + _frameListRect.xMin;
                        float end = (j+1) * _frameWidth + _frameListRect.xMin;
                        var frameRect = Rect.MinMaxRect(start, timeBarRect.yMin, end-1, timeBarRect.yMax);
                    
                        var color = _GetBGColor(i,false);
                        color = moveList[j].hasPosition ? Color.blue : Color.white;
                        _DrawFrameBar(frameRect, color, 1);
                    }
                }
               

                //Common.DrawColorBox(new Rect(timeBarRect.x, timeBarRect.y, timeBarRect.width, 1), "", Color.black * 0.1f); //画条线
                uiHeight += lineHeight;
            }
            timeFrameY = new Vector2(titleHeight,titleHeight + lineHeight * 6);
            actionFrameY = new Vector2(titleHeight + lineHeight,titleHeight + lineHeight * 2);
            eventFrameY = new Vector2(titleHeight + 3 * lineHeight,titleHeight + lineHeight * 4);
            moveFrameY = new Vector2(titleHeight + 5 * lineHeight,titleHeight + lineHeight * 6);
        }

        private EventType lastType;
        
        private void UpdateInput()
        {
            if (Event.current.type == EventType.MouseDown)
            {
                var frame = GetActionFrameByPosition(Event.current.mousePosition);
                if (frame != -1)
                {
                    isSelectedAction = true;
                    isSelectedEvent = false;
                    isSelectedMove = false;
                    currentSelectedFrame = frame;
                    tempActionName = actionList[currentSelectedFrame].actionName;
                }
                else
                {
                    frame = GetEventFrameByPosition(Event.current.mousePosition);
                    if (frame != -1)
                    {
                        isSelectedEvent = true;
                        isSelectedAction = false;
                        isSelectedMove = false;
                        currentSelectedFrame = frame;
                        tempElementId = eventList[currentSelectedFrame].elementId.ToString();
                    }
                    else
                    {
                        frame = GetMoveFrameByPosition(Event.current.mousePosition);
                        if (frame != -1)
                        {
                            isSelectedEvent = false;
                            isSelectedAction = false;
                            isSelectedMove = true;
                            currentSelectedFrame = frame;
                        }
                    }
                }
            }
            else if (Event.current.type == EventType.MouseDrag)
            {
                var frame = GetTimeFrameByPosition(Event.current.mousePosition);
                if (frame >= 0)
                {
                    cachedTimeScale = timeScale;
                    timeScale = 0;
                    progressX = Event.current.mousePosition.x;
                    var time = GetTimeOffsetByPosition(Event.current.mousePosition);
                    UpdatePosition(0,time,1);
                    UpdateFrame(frame);
                    sourceHero?.Update(time - lastSourceActionTime);
                    targetHero?.Update(time - lastTargetActionTime);
                }
            }
            else if (Event.current.type == EventType.MouseUp)
            {
                if (cachedTimeScale != 0 && lastType == EventType.MouseDrag)
                {
                    timeScale = cachedTimeScale;
                    cachedTimeScale = 0;
                }
            }

            lastType = Event.current.type;
        }

        private string tempActionName;
        private string tempElementId;
        
        private void DrawActionInfo()
        {
            uiHeight += 20;
            infoRect = Rect.MinMaxRect(_timelineMargin.x,uiHeight,_timelineMargin.x + 200,uiHeight + 100);
            if (currentSelectedFrame > -1)
            {
                var selectedFrame = actionList[currentSelectedFrame];
                GUI.Label(new Rect(_timelineMargin.x,uiHeight,100,20),string.Format("第{0}帧动画信息",currentSelectedFrame));
                uiHeight += 20;
                
                GUI.Label(new Rect(_timelineMargin.x,uiHeight,100,20),"播放：");
                tempActionName = GUI.TextField(new Rect(_timelineMargin.x + 100, uiHeight, 100, 20),
                    tempActionName);
                uiHeight += 20;
                string btnContext = "保存";
                if (!selectedFrame.hasAction)
                {
                    btnContext = "添加";
                }

                if (GUI.Button(new Rect(_timelineMargin.x, uiHeight, 50, 20), btnContext))
                {
                    if (string.IsNullOrEmpty(tempActionName))
                    {
                        selectedFrame.actionName = string.Empty;
                        selectedFrame.hasAction = false;
                    }
                    else
                    {
                        selectedFrame.actionName = tempActionName;
                        selectedFrame.hasAction = true;
                    }
                }
            }
        }
        
        private void DrawEventInfo()
        {
            uiHeight += 20;
            infoRect = Rect.MinMaxRect(_timelineMargin.x,uiHeight,_timelineMargin.x + 200,uiHeight + 100);
            if (currentSelectedFrame > -1)
            {
                var selectedFrame = eventList[currentSelectedFrame];
                GUI.Label(new Rect(_timelineMargin.x,uiHeight,100,20),string.Format("第{0}帧事件信息",currentSelectedFrame));
                uiHeight += 20;
                
                GUI.Label(new Rect(_timelineMargin.x,uiHeight,100,20),"元素id：");
                tempElementId = GUI.TextField(new Rect(_timelineMargin.x + 100, uiHeight, 100, 20),
                    tempElementId);
                uiHeight += 20;
                string btnContext = "保存";
                /*if (!selectedFrame.hasAction)
                {
                    btnContext = "添加";
                }*/

                if (GUI.Button(new Rect(_timelineMargin.x, uiHeight, 50, 20), btnContext))
                {
                    if (string.IsNullOrEmpty(tempElementId))
                    {
                        selectedFrame.elementId = 0;
                    }
                    else
                    {
                        int elementId;
                        int.TryParse(tempElementId, out elementId);
                        selectedFrame.elementId = elementId;
                    }
                }
            }
        }
        
        private void DrawMoveInfo()
        {
            uiHeight += 20;
            infoRect = Rect.MinMaxRect(_timelineMargin.x,uiHeight,_timelineMargin.x + 200,uiHeight + 100);
            if (currentSelectedFrame > -1)
            {
                var selectedFrame = moveList[currentSelectedFrame];
                GUI.Label(new Rect(_timelineMargin.x,uiHeight,120,20),string.Format("第{0}帧移动信息",currentSelectedFrame));
                uiHeight += 20;

                if (selectedFrame.hasPosition)
                {
                    GUI.Label(new Rect(_timelineMargin.x,uiHeight,400,20),"关键坐标：" + selectedFrame.position);
                    uiHeight += 20;
                    if (GUI.Button(new Rect(_timelineMargin.x, uiHeight, 120, 20), "获取当前坐标"))
                    {
                        selectedFrame.position = hero.transform.position;
                    }
                    uiHeight += 20;
                    if (GUI.Button(new Rect(_timelineMargin.x, uiHeight, 40, 20), "删除"))
                    {
                        selectedFrame.hasPosition = false;
                        selectedFrame.position = Vector3.zero;
                    }
                }
                else
                {
                    //GUI.Label(new Rect(_timelineMargin.x, uiHeight, 100, 20), "无信息");
                    GUI.Label(new Rect(_timelineMargin.x,uiHeight,400,20),"过渡坐标：" + selectedFrame.position);
                    uiHeight += 20;
                    if (GUI.Button(new Rect(_timelineMargin.x, uiHeight, 120, 20), "获取当前坐标"))
                    {
                        selectedFrame.position = hero.transform.position;
                    }
                    uiHeight += 20;
                    if (GUI.Button(new Rect(_timelineMargin.x, uiHeight, 40, 20), "保存"))
                    {
                        selectedFrame.hasPosition = true;
                    }
                }
            }
        }
        
        private void _DrawFrameBar(Rect position, Color color, float heightScale)
        {
            var center = position.center;
            position.height *= heightScale;
            position.center = center;

            var orgColor = GUI.color;
            GUI.color = color;

            GUI.DrawTexture(position, EditorGUIUtility.whiteTexture);  
       
            GUI.color = orgColor;  
        }
        
        
        private void DrawFrameLine(Rect rect,float step)
        {
            Handles.BeginGUI();
            Handles.color = Color.red;
            int Index = 0;
            for (float i = rect.x+5; i < rect.width; i+=step)
            {
                if (Index%5 == 0)
                {
                    Handles.DrawLine(new Vector3(i, rect.y), new Vector3(i, rect.y + rect.height));
                    string str = Index.ToString();
                    if (str.Length>2)
                    {
                        GUI.Label(new Rect(i - 15, rect.y, 30, 12), str);
                    }
                    else if(str.Length>1)
                    {
                        GUI.Label(new Rect(i - 10, rect.y, 20, 12), str);
                    }
                    else
                    {
                        GUI.Label(new Rect(i - 5, rect.y, 12, 12), str);
                    }
                
                }
                else
                {
                    Handles.DrawLine(new Vector3(i, rect.y + 10), new Vector3(i, rect.y + rect.height));
                }
                Index++;
            
            }
        
            Handles.EndGUI();
        }

        private float GetTimeOffsetByPosition(Vector2 mousePosition)
        {
            float offset = mousePosition.x - _frameListRect.xMin;
            if (mousePosition.y <= timeFrameY.y && mousePosition.y >= timeFrameY.x)
            {
                return (offset / _frameWidth / 30f);
            }

            return -1;
        }
        
        private int GetTimeFrameByPosition(Vector2 mousePosition)
        {
            float offset = mousePosition.x - _frameListRect.xMin;
            if (mousePosition.y <= timeFrameY.y && mousePosition.y >= timeFrameY.x)
            {
                return (int)(offset / _frameWidth);
            }

            return -1;
        }
        
        private int GetActionFrameByPosition(Vector2 mousePosition)
        {
            float offset = mousePosition.x - _frameListRect.xMin;
            if (mousePosition.y <= actionFrameY.y && mousePosition.y >= actionFrameY.x)
            {
                return (int)(offset / _frameWidth);
            }

            return -1;
        }
        
        private int GetEventFrameByPosition(Vector2 mousePosition)
        {
            float offset = mousePosition.x - _frameListRect.xMin;
            if (mousePosition.y <= eventFrameY.y && mousePosition.y >= eventFrameY.x)
            {
                return (int)(offset / _frameWidth);
            }

            return -1;
        }

        private int GetMoveFrameByPosition(Vector2 mousePosition)
        {
            float offset = mousePosition.x - _frameListRect.xMin;
            if (mousePosition.y <= moveFrameY.y && mousePosition.y >= moveFrameY.x)
            {
                return (int)(offset / _frameWidth);
            }

            return -1;
        }

        
        
        Color _GetDividedColor(Color baseColor)
        {
            var _dividedColor = baseColor * 0.8f;
            _dividedColor.a = baseColor.a;
            return _dividedColor;
        }
        
        Color _GetBGColor(int i, bool isDiveded = true)
        {
            bool selected = false;
           
            Color color;
           
            color = selected ? ActionColorSet.normalSelected : ActionColorSet.normal;

            if (i % 2 == 1 && selected == false && isDiveded)
                color = _GetDividedColor(color);

            return color;
        }
    }
}